package com.atguigu.tingshu.order.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.atguigu.tingshu.album.client.AlbumInfoFeignClient;
import com.atguigu.tingshu.common.constant.SystemConstant;
import com.atguigu.tingshu.common.execption.GuiguException;
import com.atguigu.tingshu.common.rabbit.constant.MqConst;
import com.atguigu.tingshu.common.rabbit.service.RabbitService;
import com.atguigu.tingshu.common.result.Result;
import com.atguigu.tingshu.common.result.ResultCodeEnum;
import com.atguigu.tingshu.common.util.AuthContextHolder;
import com.atguigu.tingshu.common.util.MD5;
import com.atguigu.tingshu.model.album.AlbumInfo;
import com.atguigu.tingshu.model.album.TrackInfo;
import com.atguigu.tingshu.model.order.LocalMsg;
import com.atguigu.tingshu.model.order.OrderDerate;
import com.atguigu.tingshu.model.order.OrderDetail;
import com.atguigu.tingshu.model.order.OrderInfo;
import com.atguigu.tingshu.model.user.VipServiceConfig;
import com.atguigu.tingshu.order.adapter.PayWay;
import com.atguigu.tingshu.order.helper.SignHelper;
import com.atguigu.tingshu.order.mapper.LocalMsgMapper;
import com.atguigu.tingshu.order.mapper.OrderDerateMapper;
import com.atguigu.tingshu.order.mapper.OrderDetailMapper;
import com.atguigu.tingshu.order.mapper.OrderInfoMapper;
import com.atguigu.tingshu.order.service.OrderInfoService;
import com.atguigu.tingshu.user.client.UserInfoFeignClient;
import com.atguigu.tingshu.vo.order.OrderDerateVo;
import com.atguigu.tingshu.vo.order.OrderDetailVo;
import com.atguigu.tingshu.vo.order.OrderInfoVo;
import com.atguigu.tingshu.vo.order.TradeVo;
import com.atguigu.tingshu.vo.user.UserInfoVo;
import com.atguigu.tingshu.vo.user.UserPaidRecordVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Lists;
import io.micrometer.common.util.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.RandomStringUtils;
import org.aspectj.weaver.ast.Or;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.stream.Collectors;


@Slf4j
@Service
@SuppressWarnings({"unchecked", "rawtypes"})
public class OrderInfoServiceImpl extends ServiceImpl<OrderInfoMapper, OrderInfo> implements OrderInfoService {

    @Autowired
    private OrderInfoMapper orderInfoMapper;


    @Autowired
    private UserInfoFeignClient userInfoFeignClient;

    @Autowired
    private AlbumInfoFeignClient albumInfoFeignClient;

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Autowired
    private List<PayWay> payWays;

    @Autowired
    private OrderDerateMapper orderDerateMapper;

    @Autowired
    private OrderDetailMapper orderDetailMapper;


    @Autowired
    private LocalMsgMapper localMsgMapper;

    @Autowired
    private RabbitService rabbitService;

    @Override
    public OrderInfoVo trade(TradeVo tradeVo) {
        //获取当前用户id
        Long userId = AuthContextHolder.getUserId();

        // 1.获取付款项类型（1001：专辑 1002：声音 1003：vip套餐）
        String itemType = tradeVo.getItemType();
        //初始化订单信息对象
        OrderInfoVo orderInfoVo = switch (itemType) {
            case SystemConstant.ORDER_ITEM_TYPE_ALBUM -> dealAlbumTypeItem(tradeVo, userId, itemType);
            case SystemConstant.ORDER_ITEM_TYPE_TRACK -> dealTrackTypeItem(tradeVo, userId, itemType);
            case SystemConstant.ORDER_ITEM_TYPE_VIP -> dealVipTypeItem(tradeVo, userId, itemType);
            default -> throw new IllegalStateException("参数类型错误: " + itemType);
        };
        //2.分别处理付款项类型

        //3.生成签名
        String sign = SignHelper.getSign(
                JSONObject.parseObject(
                        JSONObject.toJSONString(orderInfoVo), Map.class));
        //4.设置签名(未来在提交订单，判断提交订单的幂等性:判断多次提交的订单是否是同一笔订单)
        orderInfoVo.setSign(sign);

        //5.从订单信息中提取支付产品的ID列表
        List<Long> payProductIds = orderInfoVo.getOrderDetailVoList()
                .stream()
                .map(OrderDetailVo::getItemId)
                .toList();
        //6.对支付产品ID列表进行加密
        String encrypt = MD5.encrypt(payProductIds.toString());
        String multiportRepeatKey = "userId:" + userId + ":" + encrypt;//生成多端口重复提交订单的key
        //7.将多端重复键值保存到redis中，用来校验多端订单重复提交，键值为1
        redisTemplate.opsForValue().set(multiportRepeatKey, "1");
        log.info("订单信息：{}", orderInfoVo);
        return orderInfoVo;
    }

    @Override
    public Map<String, Object> submitOrder(OrderInfoVo orderInfoVo) {
        //1.获取当前用户id
        Long userId = AuthContextHolder.getUserId();
        // 1.校验（非法请求校验 限流  黑白名单校验 订单完整性【签名】）
        // 1.1非法请求校验
        Assert.notNull(orderInfoVo.getTimestamp(), "时间戳不能为空");
        String tradeNo = orderInfoVo.getTradeNo();//获取订单号
        if (StringUtils.isEmpty(tradeNo)) {
            throw new GuiguException(ResultCodeEnum.ORDER_NO_EMPTY);
        }
        // 1.2黑白名单校验，签名校验(防止订单信息被篡改)
        String orderInfoVoStr = JSONObject.toJSONString(orderInfoVo);//将订单信息序列化为json字符串
        HashMap checkMap = JSONObject.parseObject(orderInfoVoStr, HashMap.class);//将订单信息json串序列化为map
        checkMap.put("payWay", "");//加签的时候payWay为空，所以此时payWay字段必须置空，防止签名校验失败
        SignHelper.checkSign(checkMap);//签名校验

        // 1.3 防止订单重复提交（订单数据的幂等性）：
        //      接口幂等性：对同一接口发送的请求，不管是多少次，得到的结果应该都是一样的。
        // 面试必问：接口幂等性如何保证：
        //  1、各种锁机制（分布式 本地锁）
        //  2、Redis+Token(判断和删除作为原子操作且要放到业务代码执行之前做)
        //  3、数据库的唯一索引+防重表+十事务机制...

        List<Long> itemIds = orderInfoVo.getOrderDetailVoList()
                .stream()
                .map(OrderDetailVo::getItemId)
                .toList();// 从订单信息中提取所有商品ID到一个List中
        String encrypt = MD5.encrypt(itemIds.toString());// 对itemIds进行MD5加密
        String checkMultiPortKey = "userId:" + userId + ":" + encrypt;// 生成一个唯一标识符(用来检查多端口的密钥)
        String script = """
                if redis.call("exists", KEYS[1])
                then
                    return redis.call("del", KEYS[1])
                else
                    return 0
                end
                """;
        // 执行Redis脚本并获取long类型的返回值
        Long execute = redisTemplate.execute(new DefaultRedisScript<Long>(script, Long.class), List.of(checkMultiPortKey));
        // 判断返回值，如果返回值是0，则说明订单重复提交，无法继续执行后续操作。
        if (execute != null && execute == 0L) {
            // 重复提交
            throw new GuiguException(ResultCodeEnum.REPEAT_SUBMIT);
        }
        // 1.4生成订单编号
        String orderNo = RandomStringUtils.random(12, true, true);

        // 1.5支付方式
        // a) 判断支付方式（传统方式if else if else  switch case  设计模式：适配器模式）
        // b) 执行不同支付方式逻辑
        String payWay = orderInfoVo.getPayWay();// 获取支付方式

        // 遍历支持的支付方式列表，寻找匹配当前订单支付方式的支付方式实例
        for (PayWay supportPayWay : payWays) {
            // 检查当前支付方式实例是否支持订单中的支付方式
            if (supportPayWay.supportPayWay(payWay)) {
                // 执行匹配支付方式的支付逻辑
                supportPayWay.payWay(orderInfoVo, orderNo, userId);
            }
        }
        // 返回订单编号
        return (Map<String, Object>) new HashMap<>().put("orderNo", orderNo);
    }

    @Override
    public OrderInfo saveOrderInfo(String orderNo, OrderInfoVo orderInfoVo, Long userId) {
        //1.初始化订单信息对象
        OrderInfo orderInfo = new OrderInfo();
        try {
            // 1.保存订单基本信息
            orderInfo = saveOrderBasicInfo(orderNo, orderInfoVo, userId);

            // 2.保存订单减免信息
            saveOrderDerateInfo(orderInfoVo, orderInfo.getId());

            // 3.保存订单详情信息
            saveOrderDetailInfo(orderInfoVo, orderInfo.getId());
        } catch (Exception e) {
            // 如果保存订单信息失败，则抛出异常
            throw new GuiguException(ResultCodeEnum.ORDER_SAVE_ERROR);
        }
        return orderInfo;
    }

    /**
     * 保存订单基本信息
     *
     * @param orderNo
     * @return
     */
    @Override
    public void saveLocalMsg(String orderNo) {
        // 1.初始化订单消息对象
        LocalMsg localMsg = new LocalMsg();
        // 2.保存订单消息对象
        localMsg.setMsgContent(orderNo);
        localMsg.setStatus(0);
        localMsg.setCreateTime(new Date());
        localMsg.setUpdateTime(new Date());
        localMsgMapper.insert(localMsg);
    }

    /**
     * 根据订单号查询订单信息带详情和减免和支付名字以及状态名字
     *
     * @param orderNo
     * @return
     */
    @Override
    public OrderInfo getOrderInfoAndDetail(String orderNo) {
        // 1.根据订单号查询订单基本信息
        OrderInfo orderInfo = orderInfoMapper.selectOne(
                new LambdaQueryWrapper<OrderInfo>()
                        .eq(OrderInfo::getOrderNo, orderNo)
                        .eq(OrderInfo::getIsDeleted, 0)
        );
        if (orderInfo == null) {
            //订单不存在
            throw new GuiguException(ResultCodeEnum.ORDER_NOT_EXIST);
        }
        // 2.查询订单详情数据
        List<OrderDetail> orderDetailList = orderDetailMapper.selectList(
                new LambdaQueryWrapper<OrderDetail>()
                        .eq(OrderDetail::getOrderId, orderInfo.getId())
                        .eq(OrderDetail::getIsDeleted, 0)
        );
        // 3.查询订单减免数据
        List<OrderDerate> orderDerateList = orderDerateMapper.selectList(
                new LambdaQueryWrapper<OrderDerate>()
                        .eq(OrderDerate::getOrderId, orderInfo.getId())
                        .eq(OrderDerate::getIsDeleted, 0)
        );
        // 4.查询订单状态名字(0901 0902 0903)
        String orderStatus = orderInfo.getOrderStatus();
        String orderStatusName = getOrderStatusName(orderStatus);
        // 5.查询订单支付方式的名字(1101 1102 1103)
        String payWay = orderInfo.getPayWay();
        String payWayName = getPayWayName(payWay);
        // 6.封装数据
        orderInfo.setOrderStatusName(orderStatusName);
        orderInfo.setPayWayName(payWayName);
        orderInfo.setOrderDetailList(orderDetailList);
        orderInfo.setOrderDerateList(orderDerateList);
        return orderInfo;
    }

    /**
     * 根据支付类型获取支付类型名字
     * @param payWay
     * @return
     */
    @NotNull
    private static String getPayWayName(String payWay) {
        return switch (payWay) {
            case "1101" -> "微信支付";
            case "1102" -> "支付宝支付";
            case "1103" -> "账户余额支付";
            default -> "";
        };
    }

    /**
     * 根据订单状态获取订单状态名字
     * @param orderStatus
     * @return
     */
    @NotNull
    private static String getOrderStatusName(String orderStatus) {
        return switch (orderStatus) {
            case "0901" -> "未支付";
            case "0902" -> "已支付";
            case "0903" -> "已关闭";
            default -> "";
        };
    }

    /**
     * 支付成功后做的事
     *
     * @param orderNo
     */
    @Override
    public void paySuccess(String orderNo) {
        // 1.根据订单编号查询订单信息
        OrderInfo orderInfo = orderInfoMapper.selectOne(
                new LambdaQueryWrapper<OrderInfo>()
                        .eq(OrderInfo::getOrderNo, orderNo)
                        .eq(OrderInfo::getIsDeleted, 0)
        );
        if (orderInfo == null) {
            // 订单不存在
            throw new GuiguException(ResultCodeEnum.ORDER_NOT_EXIST);
        }
        // 2.修改订单状态
        int count = orderInfoMapper.updateOrderStatus(orderNo,SystemConstant.ORDER_STATUS_PAID);
        if (count == 0) {
            log.error("订单状态未修改成功");
        } else {
            log.info("订单状态修改成功");
        }
        // 3.记录订单支付流水（3种情况）
        UserPaidRecordVo userPaidRecordVo = new UserPaidRecordVo();
        userPaidRecordVo.setOrderNo(orderInfo.getOrderNo());
        userPaidRecordVo.setUserId(orderInfo.getUserId());
        userPaidRecordVo.setItemType(orderInfo.getItemType());// 付款项类型
        userPaidRecordVo.setItemIdList(orderInfo.getOrderDetailList()
                .stream()
                .map(OrderDetail::getItemId)
                .collect(Collectors.toList()));
        //3.1 发送消息到用户服务
        rabbitService.sendMessage(
                MqConst.EXCHANGE_USER, // 用户交换机
                MqConst.ROUTING_USER_PAY_RECORD, //用户支付记录路由
                JSONObject.toJSONString(userPaidRecordVo));
        //3.2 修改ES中专辑的购买量
        rabbitService.sendMessage(
                MqConst.EXCHANGE_ALBUM_ES_STATA_UPDATE, // 专辑状态更新交换机
                MqConst.ROUTING_ALBUM_ES_STAT_UPDATE, // 专辑状态更新路由
                orderNo);
        //3.3 修改专辑的购买量
        rabbitService.sendMessage(
                MqConst.EXCHANGE_ALBUM, // 专辑交换机
                MqConst.ROUTING_ALBUM_STAT_UPDATE,// 专辑状态更新路由
                orderNo);
    }

    /**
     * 根据用户id分页查询订单信息
     *
     * @param orderInfoPage
     * @param userId
     * @return
     */
    @Override
    public IPage<OrderInfo> findUserPage(IPage<OrderInfo> orderInfoPage, Long userId) {
        // 1.分页查询当前用户的所有订单
        List<OrderInfo> orderInfoList = orderInfoMapper.selectPage(orderInfoPage,
                new LambdaQueryWrapper<OrderInfo>()
                        .eq(OrderInfo::getUserId, userId)
                        .eq(OrderInfo::getIsDeleted, 0)
                        .orderByDesc(OrderInfo::getCreateTime)
        ).getRecords();

        // 2.遍历订单集合，获取订单详情集合，封装到订单集合中
        orderInfoList.forEach(
                orderInfo -> {
                    //设置订单状态名字
                    orderInfo.setOrderStatusName(
                            getOrderStatusName(orderInfo.getOrderStatus())
                    );
                    //设置订单详情集合
                    orderInfo.setOrderDetailList(
                            orderDetailMapper.selectList(
                                    new LambdaQueryWrapper<OrderDetail>()
                                            .eq(OrderDetail::getOrderId, orderInfo.getId())
                                            .eq(OrderDetail::getIsDeleted, 0)
                            )
                    );
                    //设置订单减免集合
                    orderInfo.setOrderDerateList(
                            orderDerateMapper.selectList(
                                    new LambdaQueryWrapper<OrderDerate>()
                                            .eq(OrderDerate::getOrderId, orderInfo.getId())
                                            .eq(OrderDerate::getIsDeleted, 0)
                            )
                    );
                    //设置订单总金额
                    orderInfo.setOrderAmount(
                            orderInfo.getOrderDetailList()
                                    .stream()
                                    .map(OrderDetail::getItemPrice)
                                    .reduce(BigDecimal.ZERO, BigDecimal::add)
                    );
                    //设置支付方式名字
                    orderInfo.setPayWayName(
                            getPayWayName(orderInfo.getPayWay())
                    );
                }
        );
        // 返回分页数据
        return orderInfoPage.setRecords(orderInfoList);
    }

    @Override
    public void cancelOrder(String content) {
        orderInfoMapper.cancelOrder(content,SystemConstant.ORDER_STATUS_CANCEL);
    }

    /**
     * 保存订单详情信息
     *
     * @param orderInfoVo
     * @param orderId
     */
    private void saveOrderDetailInfo(OrderInfoVo orderInfoVo, Long orderId) {
        orderInfoVo.getOrderDetailVoList().forEach(
                orderDetailVo -> {
                    // 1.初始化订单详情信息对象
                    OrderDetail orderDetail = new OrderDetail();
                    BeanUtils.copyProperties(orderDetailVo, orderDetail);
                    orderDetail.setOrderId(orderId);
                    orderDetailMapper.insert(orderDetail);
                });
    }

    /**
     * 保存订单减免信息
     *
     * @param orderInfoVo
     * @param orderId
     */
    private void saveOrderDerateInfo(OrderInfoVo orderInfoVo, Long orderId) {
        orderInfoVo.getOrderDerateVoList()
                .forEach(
                        orderDerateVo -> {
                            // 1.初始化订单减免信息对象
                            OrderDerate orderDerate = new OrderDerate();
                            BeanUtils.copyProperties(orderDerateVo, orderDerate);
                            orderDerate.setOrderId(orderId);
                            int insert = orderDerateMapper.insert(orderDerate);
                            log.info("保存订单减免信息到数据库{}", insert > 0 ? "成功" : "失败");
                        }
                );
    }

    /**
     * 保存订单基本信息
     *
     * @param orderNo
     * @param orderInfoVo
     * @param userId
     * @return
     */
    private OrderInfo saveOrderBasicInfo(String orderNo, OrderInfoVo orderInfoVo, Long userId) {
        OrderInfo orderInfo = new OrderInfo();
        BeanUtils.copyProperties(orderInfoVo, orderInfo);
        orderInfo.setOrderNo(orderNo);
        orderInfo.setUserId(userId);
        orderInfo.setOrderStatus("0901");
        orderInfo.setOrderTitle(orderInfoVo.getOrderDetailVoList().get(0).getItemName());
        int count = baseMapper.insert(orderInfo);
        log.info("保存订单信息到数据库{}", count > 0 ? "成功" : "失败");
        return orderInfo;
    }

    /**
     * 处理vip类型付款项
     *
     * @param tradeVo
     * @param userId
     * @param itemType
     * @return
     */
    private OrderInfoVo dealVipTypeItem(TradeVo tradeVo, Long userId, String itemType) {
        // 1.获取套餐id
        Long itemId = tradeVo.getItemId();
        //初始化订单信息对象
        OrderInfoVo orderInfoVo = new OrderInfoVo();

        // 2.1校验付款项vip是否存在支付中
        int count = orderInfoMapper.checkAlbumAndVipTypeItemPadding(itemType, userId, itemId);
        if (count != 0) {
            log.error("该付款项vip套餐：{}，处于购买中，请勿继续购买该专辑", itemId);
            orderInfoVo.setExitItemIds(Lists.newArrayList(itemId));
            return orderInfoVo;
        }

        // 3. 赋值
        orderInfoVo.setTradeNo(RandomStringUtils.random(12, true, true));
        orderInfoVo.setPayWay("");
        orderInfoVo.setItemType(itemType);

        // 3.1 获取套餐信息
        Result<VipServiceConfig> vipServiceConfigResult = userInfoFeignClient.getAllVipConfig(itemId);
        VipServiceConfig serviceConfigData = vipServiceConfigResult.getData();
        Assert.notNull(serviceConfigData, "远程查询用户微服务获取vip套餐失败");

        // 3.2 获取套餐价格
        BigDecimal price = serviceConfigData.getPrice();
        orderInfoVo.setOriginalAmount(price.setScale(2, RoundingMode.HALF_UP));
        BigDecimal discountPrice = serviceConfigData.getDiscountPrice();
        BigDecimal derateAmount = price.subtract(discountPrice).setScale(2, RoundingMode.HALF_UP);
        orderInfoVo.setDerateAmount(derateAmount); // 优惠了多少
        orderInfoVo.setOrderAmount(discountPrice.setScale(2, RoundingMode.HALF_UP)); // 实际金额

        // 3.3 给订单项属性赋值
        List<OrderDetailVo> orderDetailVos = new ArrayList<>();
        OrderDetailVo orderDetailVo = new OrderDetailVo();
        orderDetailVo.setItemId(itemId);
        orderDetailVo.setItemName(serviceConfigData.getName());
        orderDetailVo.setItemUrl(serviceConfigData.getImageUrl());
        orderDetailVo.setItemPrice(discountPrice.setScale(2, RoundingMode.HALF_UP));
        orderDetailVos.add(orderDetailVo);
        orderInfoVo.setOrderDetailVoList(Lists.newArrayList(orderDetailVos));

        // 3.4 给订单减免属性赋值
        ArrayList<OrderDerateVo> orderDerateVos = new ArrayList<>();
        OrderDerateVo orderDerateVo = new OrderDerateVo();
        orderDerateVo.setDerateType("VIP服务折扣");
        orderDerateVo.setDerateAmount(derateAmount);
        orderDerateVo.setRemarks("订单减免类型1406-VIP服务折扣");
        orderDerateVos.add(orderDerateVo);

        orderInfoVo.setOrderDerateVoList(Lists.newArrayList(orderDerateVos));
        orderInfoVo.setTimestamp(System.currentTimeMillis());
        return orderInfoVo;
    }

    /**
     * 处理声音类型付款项
     *
     * @param tradeVo
     * @param userId
     * @param itemType
     * @return
     */
    private OrderInfoVo dealTrackTypeItem(TradeVo tradeVo, Long userId, String itemType) {
        OrderInfoVo orderInfoVo = new OrderInfoVo();
        Long trackId = tradeVo.getItemId();
        Integer trackCount = tradeVo.getTrackCount(); // 购买的声音集数（本集 后10集 后20集）
        Result<TrackInfo> trackInfoResult = albumInfoFeignClient.getTrackInfoById(trackId);
        TrackInfo trackInfoData = trackInfoResult.getData();
        Assert.notNull(trackInfoData, "远程查询专辑微服务获取声音信息失败");
        Long albumId = trackInfoData.getAlbumId();
        Result<AlbumInfo> alumInfoResult = albumInfoFeignClient.getAlbumInfo(albumId);
        AlbumInfo albumInfoData = alumInfoResult.getData();
        Assert.notNull(albumInfoData, "远程查询专辑微服务获取专辑信息失败");
        // 2.幂等性校验
        // 2.1 综合方法（即能把买过的声音查询出来又能把买过的声音过滤掉 返回真正能买的声音）判断购买项是否已经买过（支付完毕）
        Result<List> canPayTrackList = albumInfoFeignClient.getPaidTrackAndFilterCanPayTrack(albumId, userId, trackCount, trackId);
        Integer code = canPayTrackList.getCode();
        // 有已经买过的声音
        if (code == 400) {
            List data = canPayTrackList.getData();
            // 将已经买过的声音返回
            orderInfoVo.setExitItemIds(data);
            return orderInfoVo;
        }
        // 经过一次过滤之后能买的声音
        List<Map> canPayTrackListData = canPayTrackList.getData();
        Assert.notNull(canPayTrackListData, "远程查询专辑微服务获取能购买的声音列表失败");

        // 2.2 判断要买的声音中有没有存在正在支付中的
        // a)将正在支付中的声音返回给前端（错误）
        // b)将不在支付中的声音返给前端（真正要展示）
        List<Long> paddingTrackIds = orderInfoMapper.checkTrackTypeItemPadding(itemType, userId);

        List<Map> paddingTrackIdList = canPayTrackListData.stream().filter(map -> paddingTrackIds.contains(map.get("id"))).toList();
        List<Object> exitTrackList = new ArrayList<>();
        // 要买的有声音中有存在支付中，收集起来返回给前端
        if (!CollectionUtils.isEmpty(paddingTrackIdList)) {
            for (Map map : paddingTrackIdList) {
                exitTrackList.add(map.get("id"));
                log.error("该付款项声音：{}，处于购买中，请勿继续购买该声音", map.get("id"));
            }
            // 收集起来返给前端
            orderInfoVo.setExitItemIds(exitTrackList);
            return orderInfoVo;
        } else {
            orderInfoVo.setTradeNo(RandomStringUtils.random(12, true, true));
            orderInfoVo.setPayWay("");
            orderInfoVo.setItemType(tradeVo.getItemType());
            BigDecimal trackPrice = albumInfoData.getPrice();
            BigDecimal originAmount = trackCount == 0 ? trackPrice : trackPrice.multiply(new BigDecimal(trackCount));
            orderInfoVo.setOriginalAmount(originAmount.setScale(2, RoundingMode.HALF_UP)); // 原始价格
            orderInfoVo.setDerateAmount(new BigDecimal("0.00")); // 优惠价格
            orderInfoVo.setOrderAmount(originAmount.setScale(2, RoundingMode.HALF_UP));// 实际金额
            ArrayList<OrderDetailVo> orderDetailVos = new ArrayList<>();
            for (Map map : canPayTrackListData) {
                OrderDetailVo orderDetailVo = new OrderDetailVo();
                Object id = map.get("id");
                orderDetailVo.setItemId(Long.parseLong(id + ""));
                orderDetailVo.setItemName((String) map.get("trackTitle"));
                orderDetailVo.setItemUrl((String) map.get("coverUrl"));
                orderDetailVo.setItemPrice(trackPrice.setScale(2, RoundingMode.HALF_UP));
                orderDetailVos.add(orderDetailVo);
            }
            orderInfoVo.setOrderDetailVoList(Lists.newArrayList(orderDetailVos));
            orderInfoVo.setOrderDerateVoList(Lists.newArrayList());// 声音不打折
            orderInfoVo.setTimestamp(System.currentTimeMillis());
            return orderInfoVo;
        }
    }

    /**
     * 处理专辑类型付款项
     *
     * @param tradeVo
     * @param userId
     * @param itemType
     * @return
     */
    private OrderInfoVo dealAlbumTypeItem(TradeVo tradeVo, Long userId, String itemType) {
        //1.初始化订单信息对象
        OrderInfoVo orderInfoVo = new OrderInfoVo();

        // 2.幂等性校验
        // 2.1 判断购买项是否已经买过（支付完毕）
        Long albumId = tradeVo.getItemId();
        //查询是否买过
        Boolean isBuy = userInfoFeignClient.getUserPaidAlbum(userId, albumId).getData();
        Assert.notNull(isBuy, "远程调用用户微服务获取购买过的专辑信息失败");
        if (isBuy) {
            log.error("该付款项目:{}已经购买过，请勿重复购买", albumId);
            throw new GuiguException(ResultCodeEnum.ORDER_BUY_ERROR);
        }
        // 2.2 判断购买项是否准备支付（支付中）
        int isPaying = orderInfoMapper.checkAlbumAndVipTypeItemPadding(itemType, userId, albumId);
        if (isPaying != 0) {
            log.error("该付款项专辑：{}，处于购买中，请勿继续购买该专辑", albumId);
            orderInfoVo.setExitItemIds(Lists.newArrayList(albumId));
            return orderInfoVo;
        } else {
            // 3.给OrderInfoVo赋值
            String tradeNo = RandomStringUtils.random(12, true, true);
            // 3.1 赋值订单交易号
            orderInfoVo.setTradeNo(tradeNo); // 订单的交易号（当订单不存在 跟踪订单信息）/订单编号（订单存在 跟踪订单信息）（跟踪订单信息）
            // 3.2 赋值订单支付方式
            orderInfoVo.setPayWay(""); // 不知道支付方式（付钱的时候才知道用哪种支付方式）
            // 3.3 赋值订单的付款项
            orderInfoVo.setItemType(tradeVo.getItemType()); // 付款项类型
            // 3.4 赋值订单的原始金额
            // 3.4.1 查询付款项的金额
            AlbumInfo albumInfoData = albumInfoFeignClient.getAlbumInfo(albumId).getData();
            Assert.notNull(albumInfoData, "远程调用专辑微服务获取专辑信息失败");
            // 付款项价格（专辑价格）
            BigDecimal originalPrice = albumInfoData.getPrice();
            // 3.4.2 设置订单的原始金额,向上保留两位小数
            orderInfoVo.setOriginalAmount(originalPrice.setScale(2, RoundingMode.HALF_UP)); // 订单的原始金额（优惠之前的价格）
            // 3.5 赋值订单的优惠金额
            // 3.5.1 查询当前登录用户对象
            UserInfoVo userInfoData = userInfoFeignClient.getUserInfo(userId).getData();
            Assert.notNull(userInfoData, "远程调用用户微服务当前登录的用户信息失败");
            // 3.5.2 判断用户是否为VIP会员
            Integer isVip = userInfoData.getIsVip();
            //初始化订单的优惠力度
            BigDecimal discount = BigDecimal.ZERO;
            if (isVip == 1) {
                // 登录用户是vip，获取vip的优惠力度
                discount = albumInfoData.getVipDiscount();
            } else {
                // 登录用户不是vip，获取普通用户的优惠力度
                discount = albumInfoData.getDiscount();
            }
            // 判断是否打折
            if (discount.intValue() == -1) {
                // 没有折扣力度（不打折）
                discount = new BigDecimal("10.00");
            }
            /// 3.5.3 计算优惠多少钱:原件：100 折扣力度：7 优惠：30=（100(原价)-[100（原价）*7（折扣力度）/10]）
            BigDecimal derateAmount = originalPrice
                    .subtract(// 100（原价）-[100（原价）*7（折扣力度）/10]
                            originalPrice.multiply(discount)
                            .divide(new BigDecimal("10.00")));
            orderInfoVo.setDerateAmount(derateAmount.setScale(2, RoundingMode.HALF_UP));// 优惠多少钱 优惠金额
            BigDecimal orderAmount = originalPrice.subtract(derateAmount);
            orderInfoVo.setOrderAmount(orderAmount.setScale(2, RoundingMode.HALF_UP));
            // 3.6 赋值订单的项数据
            ArrayList<OrderDetailVo> orderDetailVos = new ArrayList<>();
            OrderDetailVo orderDetailVo = new OrderDetailVo();
            orderDetailVo.setItemId(albumId);
            orderDetailVo.setItemName(albumInfoData.getAlbumTitle());
            orderDetailVo.setItemUrl(albumInfoData.getCoverUrl());
            orderDetailVo.setItemPrice(originalPrice); // 订单项实际金额
            orderDetailVos.add(orderDetailVo);
            orderInfoVo.setOrderDetailVoList(orderDetailVos); //订单项（到底买的是谁）信息

            // 3.7 赋值减免数据
            ArrayList<OrderDerateVo> orderDerateVos = new ArrayList<>();
            OrderDerateVo orderDerateVo = new OrderDerateVo();
            orderDerateVo.setDerateType("专辑折扣"); // 前端展示
            orderDerateVo.setDerateAmount(derateAmount); // 优惠多少
            orderDerateVo.setRemarks("订单减免类型专辑折扣减免");
            orderDerateVos.add(orderDerateVo);
            orderInfoVo.setOrderDerateVoList(Lists.newArrayList(orderDerateVos));// 减免项（到底哪个商品有减免）信息
            orderInfoVo.setTimestamp(System.currentTimeMillis());// 时间戳（未来在提交订单 判断订单失效行）

            // 4.返回订单项数据
            return orderInfoVo;
        }
    }


}
